﻿//==============================================================================  
//Copyright (C) 2012-2015 9UN.ORG. All rights reserved. 
//GUID：46172595-6b69-4526-b9da-426d663f5b05
//CLR Version: 4.0.30319.18033
//Code Author：Kevin Wang
//Contact：Email(Admin@9un.org),QQ(265382 or 74344)
//Filename：MediaInfoLibrary
//Namespace：RuanRang.Media.Core.MediaInfo
//Functions：MediaInfoLibrary  
//Created by Kevin Wang at 2013/2/2 23:05:09 http://blog.9un.org
//============================================================================== 

using System;
using System.IO;
using System.Runtime.InteropServices;
using RuanRang.Media.MediaInfo.Enums;

namespace RuanRang.Media.MediaInfo
{
    /// <summary>
    /// Provides access to the native MediaInfo API.
    /// </summary>
    public class MediaInfoLibrary : IDisposable
    {
        private readonly IntPtr _handle;

        #region Constructors & Destructors

        /// <summary>
        /// Default constructor.
        /// </summary>
        public MediaInfoLibrary()
        {
            _handle = MediaInfoInterop.MediaInfo_New();
        }

                /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        // NOTE: Leave out the finalizer altogether if this class doesn't 
        // own unmanaged resources itself, but leave the other methods
        // exactly as they are. 
        /// <summary>
        /// Finalizes an instance of the <see cref="MediaInfoLibrary" /> class.
        /// </summary>
        ~MediaInfoLibrary()
        {
            // Finalizer calls Dispose(false)
            Dispose(false);
        }

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources.
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        protected virtual void Dispose(bool disposing)
        {
            if (disposing)
            {
                // free managed resources

                // unmanaged managed resources
                Dispose(false);
                return;
            }
            MediaInfoInterop.MediaInfo_Delete(_handle);
        }

        #endregion

        #region Public Interfaces

        private bool _isAnyFileOpened;

        /// <summary>
        /// Opens a file.
        /// </summary>
        /// <param name="fileName">Name of file.</param>
        /// <returns>System.Int32.</returns>
        /// <exception cref="System.ArgumentNullException">fileName</exception>
        /// <exception cref="System.IO.FileNotFoundException">File not found</exception>
        public int OpenFile(String fileName)
        {
            if (fileName == null)
            {
                throw new ArgumentNullException("fileName");
            }
            if (!File.Exists(fileName))
            {
                throw new FileNotFoundException("File not found", fileName);
            }
            //
            if (_isAnyFileOpened)
            {
                CloseFile();
                _isAnyFileOpened = false;
            }
            var res = (int)MediaInfoInterop.MediaInfo_Open(_handle, fileName);
            _isAnyFileOpened = true;
            return (res);
        }

        /// <summary>
        /// Closes a file.
        /// </summary>
        /// <exception cref="System.ApplicationException">No media is opened now.</exception>
        public void CloseFile()
        {
            if (!_isAnyFileOpened)
            {
                throw new ApplicationException("No media is opened now.");
            }
            //
            MediaInfoInterop.MediaInfo_Close(_handle);
            _isAnyFileOpened = false;
        }

        /// <summary>
        /// Get inform string.
        /// </summary>
        /// <returns>String.</returns>
        public String Inform()
        {
            return Marshal.PtrToStringUni(MediaInfoInterop.MediaInfo_Inform(_handle, (IntPtr)0));
        }

        /// <summary>
        /// Gets description string for specified parameters.
        /// </summary>
        /// <param name="streamKind">Kind of the stream.</param>
        /// <param name="streamNumber">The stream number.</param>
        /// <param name="parameter">The parameter.</param>
        /// <param name="kindOfInfo">The kind of info.</param>
        /// <param name="kindOfSearch">The kind of search.</param>
        /// <returns>String.</returns>
        public String Get(StreamKind streamKind, int streamNumber, String parameter, InfoKind kindOfInfo, InfoKind kindOfSearch)
        {
            return Marshal.PtrToStringUni(MediaInfoInterop.MediaInfo_Get(_handle, (IntPtr)streamKind,
                (IntPtr)streamNumber, parameter, (IntPtr)kindOfInfo, (IntPtr)kindOfSearch));
        }

        /// <summary>
        /// Gets description string for specified parameters.
        /// </summary>
        /// <param name="streamKind">Kind of the stream.</param>
        /// <param name="streamNumber">The stream number.</param>
        /// <param name="parameter">The parameter.</param>
        /// <param name="kindOfInfo">The kind of info.</param>
        /// <returns>String.</returns>
        public String Get(StreamKind streamKind, int streamNumber, int parameter, InfoKind kindOfInfo)
        {
            return Marshal.PtrToStringUni(MediaInfoInterop.MediaInfo_GetI(_handle, (IntPtr)streamKind, (IntPtr)streamNumber, (IntPtr)parameter, (IntPtr)kindOfInfo));
        }

        /// <summary>
        /// Gets option string for specified parameters.
        /// </summary>
        /// <param name="option">The option.</param>
        /// <param name="value">The value.</param>
        /// <returns>String.</returns>
        /// <exception cref="System.ArgumentNullException">
        /// option
        /// or
        /// value
        /// </exception>
        public String Option(String option, String value)
        {
            if (option == null)
            {
                throw new ArgumentNullException("option");
            }
            if (value == null)
            {
                throw new ArgumentNullException("value");
            }
            //
            return Marshal.PtrToStringUni(MediaInfoInterop.MediaInfo_Option(_handle, option, value));
        }

        /// <summary>
        /// Gets state string.
        /// </summary>
        public int State_Get()
        {
            return (int)MediaInfoInterop.MediaInfo_State_Get(_handle);
        }

        /// <summary>
        /// Gets count of streams.
        /// </summary>
        /// <param name="streamKind">Kind of the stream.</param>
        /// <param name="streamNumber">The stream number.</param>
        /// <returns>System.Int32.</returns>
        public int Count_Get(StreamKind streamKind, int streamNumber)
        {
            return (int)MediaInfoInterop.MediaInfo_Count_Get(_handle, (IntPtr)streamKind, (IntPtr)streamNumber);
        }

        /// <summary>
        /// Gets description string for specified parameters.
        /// </summary>
        /// <param name="streamKind">Kind of the stream.</param>
        /// <param name="streamNumber">The stream number.</param>
        /// <param name="parameter">The parameter.</param>
        /// <param name="kindOfInfo">The kind of info.</param>
        /// <returns>String.</returns>
        public String Get(StreamKind streamKind, int streamNumber, String parameter, InfoKind kindOfInfo)
        {
            return Get(streamKind, streamNumber, parameter, kindOfInfo, InfoKind.Name);
        }

        /// <summary>
        /// Gets description string for specified parameters.
        /// </summary>
        /// <param name="streamKind">Kind of the stream.</param>
        /// <param name="streamNumber">The stream number.</param>
        /// <param name="parameter">The parameter.</param>
        /// <returns>String.</returns>
        public String Get(StreamKind streamKind, int streamNumber, String parameter)
        {
            return Get(streamKind, streamNumber, parameter, InfoKind.Text, InfoKind.Name);
        }

        /// <summary>
        /// Gets description string for specified parameters.
        /// </summary>
        /// <param name="streamKind">Kind of the stream.</param>
        /// <param name="streamNumber">The stream number.</param>
        /// <param name="parameter">The parameter.</param>
        /// <returns>String.</returns>
        public String Get(StreamKind streamKind, int streamNumber, int parameter)
        {
            return Get(streamKind, streamNumber, parameter, InfoKind.Text);
        }

        /// <summary>
        /// Gets option string for specified parameters.
        /// </summary>
        /// <param name="option">The option.</param>
        /// <returns>String.</returns>
        /// <exception cref="System.ArgumentNullException">option</exception>
        public String Option(String option)
        {
            if (option == null)
            {
                throw new ArgumentNullException("option");
            }
            //
            return Option(option, String.Empty);
        }

        /// <summary>
        /// Gets count of streams with specified type.
        /// </summary>
        /// <param name="streamKind">Kind of the stream.</param>
        /// <returns>System.Int32.</returns>
        public int Count_Get(StreamKind streamKind)
        {
            return Count_Get(streamKind, -1);
        }

        #endregion
    }
}